﻿using Gengens.Disk.Entity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Gengens.Disk.Repository
{
    public class BaseRepository<Model> : 
        IBaseRepository<Model> where Model : BaseModel<Model>
    {
        private readonly AppDbCtx _appDbctx;
        public AppDbCtx AppDbCtx => _appDbctx;

        public DbSet<Model> Models => _appDbctx.Set<Model>();

        public DatabaseFacade Database => _appDbctx.Database;

        public BaseRepository(AppDbCtx appDbCtx)
        {
            _appDbctx = appDbCtx;
        }

        #region 查询

        public virtual Model Find(Guid id)
        {
            Model? model = Models.Where(m => m.Id == id).FirstOrDefault();

            if (model == default) return default;
            if (!model.OnSelect()) return default;

            return model;
        }

        public virtual async Task<Model> FindAsync(Guid id)
        {   
            return await Models.Where(m => m.Id == id).FirstOrDefaultAsync();
        }

        public virtual List<Model> FindAll()
        {
            List<Model> data = Models.ToList();

            if (data == default || data.Count == 0) return new ();

            return data.FindAll(m => m.OnSelect());
        }

        public virtual async Task<List<Model>> FindAllAsync()
        {
            List<Model> data = await Models.ToListAsync();

            if (data == default || data.Count == 0) return new();

            return data.FindAll(m => m.OnSelect());
        }

        public virtual List<Model> Select(Func<Model, bool> whereFunc)
        {
            List<Model> data = Models.Where(whereFunc).ToList();

            if (data == default || data.Count == 0) return new();

            return data.FindAll(m => m.OnSelect());
        }

        public virtual async Task<List<Model>> SelectAsync(Func<Model, bool> whereFunc)
            => await Task.Run(()=>Select(whereFunc));

        public virtual List<Model> PageSelect(int pageSize,int pageIndex,Func<Model,bool> whereFunc)
        {
            return Select(whereFunc).Skip(pageSize * (pageIndex - 1)).Take(pageSize).ToList();
        }

        public virtual async Task<List<Model>> PageSelectAsync(int pageSize, int pageIndex, Func<Model, bool> whereFunc)
            => await Task.Run(() => PageSelectAsync(pageSize, pageIndex, whereFunc));

        #endregion

        #region 新增

        public virtual Model Insert(Model model)
        {
            if (!model.OnInsert()) return default;
            return Models.Add(model).Entity;
        }

        public virtual async Task<Model> InsertAsync(Model model)
        {
            if (!model.OnInsert()) return default;
            return (await Models.AddAsync(model)).Entity;
        }

        public virtual void InsertRange(List<Model> models)
        {
            List<Model> data = models.FindAll(m => m.OnInsert());
            if(data.Any()) Models.AddRange(data);
        }

        public virtual async Task InsertRangeAsync(List<Model> models)
        {
            List<Model> data = models.FindAll(m => m.OnInsert());
            if (data.Any()) await Models.AddRangeAsync(data);
        }

        #endregion

        #region 删除

        public virtual void Delete(Model model)
        {
            if (!model.OnDelete()) return;
            Models.Remove(model);
        }

        public virtual void DeleteRange(List<Model> models)
        {
            List<Model> data = models.FindAll(m => m.OnDelete());
            if (data.Any()) Models.RemoveRange(data);
        }

        #endregion

        #region 更新

        public void Update(Model model)
        {
            if (!model.OnUpdate()) return;
            Models.Update(model);
        }

        public void UpdateRange(List<Model> models)
        {
            List<Model> data = models.FindAll(m => m.OnUpdate());
            if(data.Any()) Models.UpdateRange(data);
        }

        #endregion

        #region 保存
        public void SaveChanges()
        {
            _appDbctx.SaveChanges();
        }

        public async Task SaveChangesAsync()
        {
            await _appDbctx.SaveChangesAsync();
        }

        #endregion

        #region 其他

        public async Task<int> ExecuteSqlRawAsync(string sql,params object[] args) {
            return await Database.ExecuteSqlRawAsync(sql, args);
        }

        #endregion
    }
}
